package com.dbw.pdftool;

import java.io.File;
import java.io.IOException;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.action.PDAction;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionGoTo;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageFitWidthDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem;
import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineNode;

public class BookmarkOptimiser {

    private String inputFilePath = null;

    public BookmarkOptimiser(String inputFilePath) {
        this.inputFilePath = inputFilePath;
    }

    private void optimise() {

        String outputFilePath = inputFilePath.replace(".pdf", "_new.pdf");
        PDDocument document = null;
        try {
            document = PDDocument.load(new File(inputFilePath));
            PDDocumentOutline outline = document.getDocumentCatalog().getDocumentOutline();
            if (outline != null) {
                optimiseBookmark(outline, "");
            } else {
                System.out.println("This document does not contain any bookmarks");
            }
            document.save(new File(outputFilePath));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (document != null) {
                try {
                    document.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public static void optimise(String inputFilePath) {
        BookmarkOptimiser optimiser = new BookmarkOptimiser(inputFilePath);
        optimiser.optimise();
    }

    private static void optimiseBookmark(PDOutlineNode bookmark, String indentation) throws IOException {
        PDOutlineItem current = bookmark.getFirstChild();

        while (current != null) {
            optimiseBookmark(current, indentation + "|__ ");

            optimiseOutlineItem(current);
            current = current.getNextSibling();
        }

    }

    private static void optimiseOutlineItem(PDOutlineItem outlineItem) throws IOException {
    	String title = outlineItem.getTitle();
    	title = title.trim();
    	outlineItem.setTitle(title);
    	
        PDDestination dest = null;
        dest = outlineItem.getDestination();
        if (dest != null) {
            outlineItem.setDestination(getOptimumPDDestination(dest));
            return;
        }

        PDAction pdAction = outlineItem.getAction();
        if (pdAction != null && pdAction instanceof PDActionGoTo) {
            PDActionGoTo pdActionGoto = (PDActionGoTo) pdAction;
            dest = pdActionGoto.getDestination();
            if (dest != null) {
                outlineItem.setAction(null);
                outlineItem.setDestination(getOptimumPDDestination(dest));
            }
        }
    }

    private static PDDestination getOptimumPDDestination(PDDestination dest) {
        if (dest == null) {
            return null;
        } else if (dest instanceof PDPageXYZDestination) {
            return convert((PDPageXYZDestination) dest);
        } else if (dest instanceof PDPageFitWidthDestination) {
            return convert((PDPageFitWidthDestination) dest);
        } else if (dest instanceof PDPageDestination) {
            return convert((PDPageDestination)dest);
        } else {
            return dest;
        }
    }

    private static PDPageXYZDestination convert(PDPageXYZDestination dest) {
        dest.setZoom(0);
        return dest;
    }

    private static PDPageXYZDestination convert(PDPageFitWidthDestination dest) {
        PDPageXYZDestination newDest = new PDPageXYZDestination();
        newDest.setTop(dest.getTop());
        newDest.setZoom(0);
        newDest.setPageNumber(dest.retrievePageNumber());
        return newDest;
    }
    
    private static PDPageXYZDestination convert(PDPageDestination dest) {
        PDPageXYZDestination newDest = new PDPageXYZDestination();
        newDest.setZoom(0);
        newDest.setPageNumber(dest.retrievePageNumber());
        return newDest;
    }
}
